home *** CD-ROM | disk | FTP | other *** search
- /* Tom Elwertowski
- *
- * ReplaceAll( sourceHndl, replaceHndl, targetHndl )
- *
- * Replace all occurrances of sourceHndl in targetHndl with
- * replaceHndl. If replace length is not greater than source
- * length, replacement can be done as search proceeds.
- * Otherwise, all occurrances must be found first in order
- * to determine how much target will grow. A recursive
- * solution is used in the latter case; matches are found
- * on the way in and replacement occurs on the way out.
- *
- * Depending upon run length, substrings are moved either
- * by a byte copy loop or by the BlockMove routine. A word
- * move loop was considered and rejected. Best performance
- * was achieved for these string sizes: byte loop: <9,
- * word loop: 9-200 and BlockMove: >200. A word loop must
- * check for and deal with word nonaligmnent however which
- * resulted in more than a few lines of code and an inline
- * solution appeared excessively cumbersome. When all three
- * approaches were put in a subroutine, the additional
- * overhead swamped the gain in most cases. The compromise
- * was to use inline code with a byte loop for substrings
- * up to 21 characters and a BlockMove otherwise.
- */
-
- #define kBlockMoveMin 22
-
- typedef struct replaceParamBlock {
- Handle sourceHndl;
- long sourceSize;
- char *sourceStart;
- char *sourceEnd;
- Handle replaceHndl;
- long replaceSize;
- char *replaceStart;
- char *replaceEnd;
- Handle targetHndl;
- long targetSize;
- char *targetStart;
- char *targetEnd;
- long deltaSize;
- } replaceParamBlock, *replaceParamBlockPtr;
-
- long replaceOne( char *target, long depth, long deltaOffset,
- replaceParamBlockPtr replacePBPtr);
-
- long ReplaceAll( Handle sourceHndl, Handle replaceHndl,
- Handle targetHndl )
- {
- replaceParamBlock replacePB;
- char *target, *targetMatch, *targetOld, *targetNew,
- *source, *replace;
- long numReplace, deltaOffset, size;
-
- replacePB.sourceHndl = sourceHndl;
- replacePB.sourceSize = GetHandleSize( sourceHndl);
- replacePB.sourceStart = *sourceHndl;
- replacePB.sourceEnd =
- replacePB.sourceStart + replacePB.sourceSize;
- replacePB.replaceHndl = replaceHndl;
- replacePB.replaceSize = GetHandleSize( replaceHndl);
- replacePB.replaceStart = *replaceHndl;
- replacePB.replaceEnd =
- replacePB.replaceStart + replacePB.replaceSize;
- replacePB.targetHndl = targetHndl;
- replacePB.targetSize = GetHandleSize( targetHndl);
- replacePB.targetStart = *targetHndl;
- replacePB.targetEnd =
- replacePB.targetStart + replacePB.targetSize;
- replacePB.deltaSize =
- replacePB.replaceSize - replacePB.sourceSize;
-
- numReplace = 0;
- deltaOffset = 0;
- if ( replacePB.deltaSize <= 0 ) {
-
- /* Iterative solution when
- * replacement not longer then source */
- target = replacePB.targetStart;
- while ( target < replacePB.targetEnd) {
- if ( *target++ == *replacePB.sourceStart ) {
-
- /* Beginning of potential match */
- targetMatch = target - 1;
- source = replacePB.sourceStart + 1;
- while ( source < replacePB.sourceEnd )
- if ( *target++ != *source++ )
- goto noMatch;
-
- /* Match encountered */
-
- /* Shift unchanged segment of target */
- if (numReplace > 0 &&
- replacePB.deltaSize < 0 ) {
- targetOld = replacePB.targetStart;
- targetNew = replacePB.targetStart +
- deltaOffset;
- size = targetMatch -
- replacePB.targetStart;
- if ( size < kBlockMoveMin )
- while ( targetOld < targetMatch )
- *targetNew++ = *targetOld++;
- else
- BlockMove( targetOld, targetNew,
- size );
- }
-
- /* Do replacement */
- replace = replacePB.replaceStart;
- targetNew = targetMatch + deltaOffset;
- if ( replacePB.replaceSize < kBlockMoveMin )
- while ( replace < replacePB.replaceEnd )
- *targetNew++ = *replace++;
- else
- BlockMove( replace, targetNew,
- replacePB.replaceSize );
-
- numReplace++;
- deltaOffset += replacePB.deltaSize;
- replacePB.targetStart = target;
- }
-
- noMatch:;
- }
-
- /* End of target encountered */
-
- /* If replacements have occurred and
- * replacement is shorter */
- if ( numReplace > 0 && replacePB.deltaSize < 0 ) {
-
- /* Compress target from last match to end */
- targetNew = replacePB.targetStart + deltaOffset;
- targetOld = replacePB.targetStart;
- size = replacePB.targetEnd -
- replacePB.targetStart;
- if ( size < kBlockMoveMin )
- while ( targetOld < replacePB.targetEnd )
- *targetNew++ = *targetOld++;
- else
- BlockMove( targetOld, targetNew, size );
-
- /* Resize target*/
- SetHandleSize ( targetHndl,
- replacePB.targetSize += deltaOffset );
- if ( MemError() != noErr)
- numReplace = -1;
- }
- }
- else
- /* Recursive solution when
- * replacement is longer than source */
- numReplace = replaceOne( replacePB.targetStart,
- 0, 0, &replacePB );
-
- return ( numReplace );
- }
-
- long replaceOne( char *targetEntry, long depth,
- long deltaOffset, replaceParamBlockPtr replacePBPtr )
- {
- char *source, *replace, *target;
- char *targetOld, *targetNew, *targetMatch;
- long targetEntryOffset, targetMatchOffset, size;
- long numReplace;
-
- target = targetEntry;
- targetEntryOffset = targetEntry -
- replacePBPtr->targetStart;
- while ( target < replacePBPtr->targetEnd ) {
- if ( *target++ == *replacePBPtr->sourceStart ) {
-
- /* Beginning of potential match */
- targetMatch = target - 1;
- targetMatchOffset = targetMatch -
- replacePBPtr->targetStart;
- source = replacePBPtr->sourceStart + 1;
- while ( source < replacePBPtr->sourceEnd )
- if ( *target++ != *source++ )
- goto noMatch;
-
- /* Match encountered. Look for next match */
- numReplace = replaceOne( target, depth + 1,
- deltaOffset + replacePBPtr->deltaSize,
- replacePBPtr );
-
- /* Expand target after all matches found */
- if ( numReplace > 0 ) {
-
- /* Do replacement */
- targetMatch = replacePBPtr->targetStart +
- targetMatchOffset;
- targetNew = targetMatch + deltaOffset;
- if ( replacePBPtr->replaceSize <
- kBlockMoveMin ) {
- targetNew += replacePBPtr->replaceSize;
- replace = replacePBPtr->replaceEnd;
- while ( replace >
- replacePBPtr->replaceStart )
- *--targetNew = *--replace;
- }
- else
- BlockMove( replacePBPtr->replaceStart,
- targetNew,
- replacePBPtr->replaceSize );
-
- /* Shift unchanged segment of target */
- if ( depth > 0 ) {
- targetOld = targetMatch;
- targetEntry =
- replacePBPtr->targetStart +
- targetEntryOffset;
- size = targetMatch - targetEntry;
- if ( size < kBlockMoveMin )
- while ( targetOld > targetEntry )
- *--targetNew = *--targetOld;
- else {
- targetNew -= size;
- BlockMove( targetEntry, targetNew,
- size );
- }
- }
- }
- return ( numReplace );
- }
- noMatch:;
- }
-
- /* End of target encountered */
- if ( depth > 0 ) {
-
- /* Resize target */
- SetHandleSize ( replacePBPtr->targetHndl,
- replacePBPtr->targetSize += deltaOffset );
- if ( MemError() == noErr) {
-
- /* Update pointers after possible relocation */
- replacePBPtr->targetStart =
- *replacePBPtr->targetHndl;
- replacePBPtr->targetEnd =
- replacePBPtr->targetStart +
- replacePBPtr->targetSize;
- replacePBPtr->replaceStart =
- *replacePBPtr->replaceHndl;
- replacePBPtr->replaceEnd =
- replacePBPtr->replaceStart +
- replacePBPtr->replaceSize;
-
- /* Expand target from last match to end */
- targetOld = replacePBPtr->targetEnd -
- deltaOffset;
- targetEntry = replacePBPtr->targetStart +
- targetEntryOffset;
- size = targetOld - targetEntry;
- if ( size < kBlockMoveMin ) {
- targetNew = replacePBPtr->targetEnd;
- while ( targetOld > targetEntry )
- *--targetNew = *--targetOld;
- }
- else {
- targetNew = targetEntry + deltaOffset;
- BlockMove( targetEntry, targetNew, size );
- }
- }
- else
- depth = -1;
- }
-
- return ( depth );
- }
-